/**
 *  Copyright 23.07.2012 oliver.keusemann@googlemail.com
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package de.xelerity.geolessi.types.verbindung;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import de.xelerity.geolessi.types.poi.Abfahrt;
import de.xelerity.helper.StringFunktionen;

public class Linie implements Serializable {

	public static final long LinienTyp_BUS = 1L << 1;
	public static final long LinienTyp_SBAHN = 1L << 2;
	public static final long LinienTyp_UBAHN = 1L << 3;
	public static final long LinienTyp_ZAHNRAD = 1L << 4;

	private static final long serialVersionUID = -903781871437629L;

	// Auch ergaenzen in Klasse 'HalteStelle' und in Methode
	// 'getLinienTypAsString'

	String Nummer = "";
	long LinienTyp = 0L;
	List<Richtung> Directions = new ArrayList<Richtung>();

	public String getNummer() {
		return Nummer == null ? "" : Nummer;
	}

	public void setNummer(String nummer) {
		Nummer = (nummer == null ? "" : nummer.trim());
	}

	public long getLinienTyp() {
		return LinienTyp;
	}

	public String getLinienTypAsString() {

		if (LinienTyp == 0L) {
			return "err";
		}
		if (LinienTyp == LinienTyp_BUS) {
			return "Bus";
		}
		if (LinienTyp == LinienTyp_SBAHN) {
			return "S-Bahn";
		}
		if (LinienTyp == LinienTyp_UBAHN) {
			return "U-Bahn";
		}
		if (LinienTyp == LinienTyp_ZAHNRAD) {
			return "ZR";
		}

		return "n/a";
	}

	public void setLinienTyp(long linienTyp) {
		LinienTyp = linienTyp;
	}

	public void addDirection(String pDirection, String pDirectionNr) {

		pDirection = pDirection == null ? "" : pDirection;
		pDirectionNr = pDirectionNr == null ? "" : pDirectionNr;

		if (StringFunktionen.isEmpty(pDirection.replaceAll("[^0-9a-zA-Z]", ""))
				&& StringFunktionen.isEmpty(pDirectionNr.replaceAll("[^0-9a-zA-Z]", ""))) {
			return;
		}
		if (!StringFunktionen.isEmpty(pDirection.replaceAll("[^0-9a-zA-Z]", ""))
				&& StringFunktionen.isEmpty(pDirectionNr.replaceAll("[^0-9a-zA-Z]", ""))) {
			pDirectionNr = "#" + Richtung.df(pDirection).hashCode();
		}

		Richtung cmpx = new Richtung(pDirection, pDirectionNr);
		for (Richtung S : Directions) {
			if (S.equals(cmpx)) {
				return;
			}
		}

		Directions.add(cmpx);
	}

	public void addDirection(String pDirection, String pDirectionNr, Abfahrt pAbfahrt, String pGleis) {

		pDirection = pDirection == null ? "" : pDirection;
		pDirectionNr = pDirectionNr == null ? "" : pDirectionNr;

		if (StringFunktionen.isEmpty(pDirection.replaceAll("[^0-9a-zA-Z]", ""))
				&& StringFunktionen.isEmpty(pDirectionNr.replaceAll("[^0-9a-zA-Z]", ""))) {
			return;
		}
		if (!StringFunktionen.isEmpty(pDirection.replaceAll("[^0-9a-zA-Z]", ""))
				&& StringFunktionen.isEmpty(pDirectionNr.replaceAll("[^0-9a-zA-Z]", ""))) {
			pDirectionNr = "#" + Richtung.df(pDirection).hashCode();
		}

		Richtung cmpx = new Richtung(pDirection, pDirectionNr, pAbfahrt, pGleis);
		for (Richtung S : Directions) {
			if (S.equals(cmpx)) {
				// System.out.println(pAbfahrt);
				// System.out.println(S.getAbfahrten().size());

				S.addAbfahrtsZeit(pAbfahrt);

				// System.out.println(S.getAbfahrten().size());

				return;
			}
		}

		Directions.add(cmpx);
	}

	public void addDirection(Richtung R) {

		if (R == null) {
			return;
		}
		addDirection(R.getDirection(), R.getDirectionNr());
	}

	public List<Richtung> getDirections() {
		return Directions == null ? new ArrayList<Richtung>() : Directions;
	}

	public String toString() {
		return getLinienTypAsString() + "" + getNummer();
	}

	public int hashCode() {
		String s = ("" + LinienTyp + Nummer).replaceAll("[^0-9a-zA-Z]", "");
		return s.hashCode();
	}

	public boolean equals(Linie L) {
		if (L == null || (L.hashCode() != hashCode())) {
			return false;
		}
		List<Integer> A = new ArrayList<Integer>();
		for (Richtung S : L.getDirections()) {
			String S1 = S.getDirection().replaceAll("[^0-9a-zA-Z]", "");
			A.add(S1.toLowerCase().hashCode());
		}
		Collections.sort(A);

		List<Integer> B = new ArrayList<Integer>();
		for (Richtung S : getDirections()) {
			String S1 = S.getDirection().replaceAll("[^0-9a-zA-Z]", "");
			B.add(S1.toLowerCase().hashCode());
		}
		Collections.sort(B);

		if (A.size() != B.size()) {
			return false;
		} else {
			for (int i = 0; i < A.size(); i++) {
				if (A.get(i).intValue() != B.get(i).intValue()) {
					return false;
				}
			}
		}
		return true;
	}

	// Input zb:
	// STB U7
	// STB
	// null if error

	public static Linie parseLinienInfo(String S) {
		return parseLinienInfo(S, true);
	}

	private static Linie parseLinienInfo(String S, boolean logerror) {
		if (StringFunktionen.isEmptyTrimed(S)) {
			return null;
		}
		S = S.trim().replaceAll("\\s+", " ");

		Linie L = new Linie();

		// STB U7
		String[] split = { "1", "0" };

		if (S.trim().matches(".*\\s+.*$")) {
			split = S.trim().replaceAll("\\s+", " ").split("\\s+");
			if (split.length != 2) {
				if (logerror) {
					Log log = LogFactory.getLog(Linie.class);
					log.error("Ungueltiges Linien, LinienNr format. Erwarte zB: 'STB U7'. Bekommen:" + S);
				}
			}
		} else {
			split[0] = S.trim();
			split[1] = "0";
		}

		// Bahn skippen (ICE, EC, RE, IC, ...)
		if (split[0].trim().matches("RB\\s*[0-9]+$")) {
			return null;
		} else if (split[0].trim().matches("IRE\\s*[0-9]+$")) {
			return null;
		} else if (split[0].trim().matches("ICE\\s*[0-9]*$")) {
			return null;
		} else if (split[0].trim().matches("EC\\s*[0-9]*$")) {
			return null;
		} else if (split[0].trim().matches("RE\\s*[0-9]*$")) {
			return null;
		} else if (split[0].trim().matches("IC\\s*[0-9]*$")) {
			return null;
		} else if (split[0].trim().toLowerCase().startsWith("zahnr")) {
			L.setLinienTyp(Linie.LinienTyp_ZAHNRAD);
		} else if (split[0].trim().equalsIgnoreCase("STB")) {
			L.setLinienTyp(Linie.LinienTyp_UBAHN);
		} else if (split[0].trim().equalsIgnoreCase("bus")) {
			L.setLinienTyp(Linie.LinienTyp_BUS);
		} else if (split[0].trim().equalsIgnoreCase("alt")) {
			L.setLinienTyp(Linie.LinienTyp_BUS);
		} else if (split[0].trim().equalsIgnoreCase("lt")) {
			L.setLinienTyp(Linie.LinienTyp_BUS);
		} else if (split[0].trim().equalsIgnoreCase("s")) {
			L.setLinienTyp(Linie.LinienTyp_SBAHN);
		} else {
			if (logerror) {
				Log log = LogFactory.getLog(Linie.class);
				log.error("Lineinzuordnung zu:'" + split[0] + "' nicht gefunden. Code ergaenzen. in: Linie.parseLinienInfo() Input:"
						+ S);
			}
			return null;
		}

		L.setNummer(split[1]);
		return L;
	}

	public static boolean isLinienToken(String S) {
		if (StringFunktionen.isEmptyTrimed(S))
			return false;
		return null != parseLinienInfo(S.replaceAll("\\s+", " ").trim().toLowerCase(), false);
	}
}
